package com.xzx.paymentdemo.util;

import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.exception.ParseException;
import com.wechat.pay.contrib.apache.httpclient.exception.ValidationException;
import com.wechat.pay.contrib.apache.httpclient.notification.Notification;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationHandler;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationRequest;
import com.xzx.paymentdemo.config.WxPayConfig;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;

import static com.wechat.pay.contrib.apache.httpclient.constant.WechatPayHttpHeaders.*;

/**
 * 回调通知的验签与解密
 *
 * @author xzx
 * @since 2022/8/12
 */
@Component
public class NotificationHandlerUtils {

    @Resource
    private Verifier verifier;
    @Resource
    private WxPayConfig wxPayConfig;

    /**
     * 验签request并解析加密数据获取订单的详情
     * @param request
     * @param body
     * @return
     */
    public String getDecryptData(HttpServletRequest request, String body) {
        String serial = request.getHeader(WECHAT_PAY_SERIAL);
        String nonce = request.getHeader(WECHAT_PAY_NONCE);
        String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP);
        String signature = request.getHeader(WECHAT_PAY_SIGNATURE);
        // 构建request，传入必要参数
        NotificationRequest req = new NotificationRequest.Builder()
                .withSerialNumber(serial)
                .withNonce(nonce)
                .withTimestamp(timestamp)
                .withSignature(signature)
                .withBody(body)
                .build();
        NotificationHandler handler = new NotificationHandler(verifier, wxPayConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8));
        // 验签和解析请求体
        Notification notification = null;
        try {
            notification = handler.parse(req);
        } catch (ValidationException e) {
            throw new RuntimeException("验签失败");
        } catch (ParseException e) {
            throw new RuntimeException("解析失败");
        }
        // 从notification中获取解密报文
        return notification.getDecryptData();
    }
}
